/*
 * Copyright 2018-2020 Yury Gribov
 *
 * The MIT License (MIT)
 *
 * Use of this source code is governed by MIT license that can be
 * found in the LICENSE.txt file.
 */

#include <dlfcn.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>

// Sanity check for ARM to avoid puzzling runtime crashes
#ifdef __arm__
# if defined __thumb__ && ! defined __THUMB_INTERWORK__
#   error "ARM trampolines need -mthumb-interwork to work in Thumb mode"
# endif
#endif

#ifdef __cplusplus
extern "C" {
#endif

#define CHECK(cond, fmt, ...) do { \
    if(!(cond)) { \
      fprintf(stderr, "implib-gen: libX11.so: " fmt "\n", ##__VA_ARGS__); \
      assert(0 && "Assertion in generated code"); \
      exit(1); \
    } \
  } while(0)

#define CALL_USER_CALLBACK 0
#define NO_DLOPEN False
#define LAZY_LOAD 1

static void *lib_handle;
static int is_lib_loading;

static void *load_library() {
  if(lib_handle)
    return lib_handle;

  is_lib_loading = 1;

  // TODO: dlopen and users callback must be protected w/ critical section (to avoid dlopening lib twice)
#if NO_DLOPEN
  CHECK(0, "internal error"); // We shouldn't get here
#elif CALL_USER_CALLBACK
  extern void *(const char *lib_name);
  lib_handle = ("libX11.so");
  CHECK(lib_handle, "callback '' failed to load library");
#else
  lib_handle = dlopen("libX11.so", RTLD_LAZY | RTLD_GLOBAL);
  CHECK(lib_handle, "failed to load library: %s", dlerror());
#endif

  is_lib_loading = 0;

  return lib_handle;
}

#if ! NO_DLOPEN && ! LAZY_LOAD
static void __attribute__((constructor)) load_lib() {
  load_library();
}
#endif

static void __attribute__((destructor)) unload_lib() {
  if(lib_handle)
    dlclose(lib_handle);
}

// TODO: convert to single 0-separated string
static const char *const sym_names[] = {
  "KeySymToUcs4",
  "XActivateScreenSaver",
  "XAddConnectionWatch",
  "XAddExtension",
  "XAddHost",
  "XAddHosts",
  "XAddPixel",
  "XAddToExtensionList",
  "XAddToSaveSet",
  "XAllPlanes",
  "XAllocClassHint",
  "XAllocColor",
  "XAllocColorCells",
  "XAllocColorPlanes",
  "XAllocIconSize",
  "XAllocNamedColor",
  "XAllocSizeHints",
  "XAllocStandardColormap",
  "XAllocWMHints",
  "XAllowEvents",
  "XAutoRepeatOff",
  "XAutoRepeatOn",
  "XBaseFontNameListOfFontSet",
  "XBell",
  "XBitmapBitOrder",
  "XBitmapPad",
  "XBitmapUnit",
  "XBlackPixel",
  "XBlackPixelOfScreen",
  "XCellsOfScreen",
  "XChangeActivePointerGrab",
  "XChangeGC",
  "XChangeKeyboardControl",
  "XChangeKeyboardMapping",
  "XChangePointerControl",
  "XChangeProperty",
  "XChangeSaveSet",
  "XChangeWindowAttributes",
  "XCheckIfEvent",
  "XCheckMaskEvent",
  "XCheckTypedEvent",
  "XCheckTypedWindowEvent",
  "XCheckWindowEvent",
  "XCirculateSubwindows",
  "XCirculateSubwindowsDown",
  "XCirculateSubwindowsUp",
  "XClearArea",
  "XClearWindow",
  "XClipBox",
  "XCloseDisplay",
  "XCloseIM",
  "XCloseOM",
  "XConfigureWindow",
  "XConnectionNumber",
  "XContextDependentDrawing",
  "XContextualDrawing",
  "XConvertCase",
  "XConvertSelection",
  "XCopyArea",
  "XCopyColormapAndFree",
  "XCopyGC",
  "XCopyPlane",
  "XCreateBitmapFromData",
  "XCreateColormap",
  "XCreateFontCursor",
  "XCreateFontSet",
  "XCreateGC",
  "XCreateGlyphCursor",
  "XCreateIC",
  "XCreateImage",
  "XCreateOC",
  "XCreatePixmap",
  "XCreatePixmapCursor",
  "XCreatePixmapFromBitmapData",
  "XCreateRegion",
  "XCreateSimpleWindow",
  "XCreateWindow",
  "XDefaultColormap",
  "XDefaultColormapOfScreen",
  "XDefaultDepth",
  "XDefaultDepthOfScreen",
  "XDefaultGC",
  "XDefaultGCOfScreen",
  "XDefaultRootWindow",
  "XDefaultScreen",
  "XDefaultScreenOfDisplay",
  "XDefaultString",
  "XDefaultVisual",
  "XDefaultVisualOfScreen",
  "XDefineCursor",
  "XDeleteContext",
  "XDeleteModifiermapEntry",
  "XDeleteProperty",
  "XDestroyIC",
  "XDestroyImage",
  "XDestroyOC",
  "XDestroyRegion",
  "XDestroySubwindows",
  "XDestroyWindow",
  "XDirectionalDependentDrawing",
  "XDisableAccessControl",
  "XDisplayCells",
  "XDisplayHeight",
  "XDisplayHeightMM",
  "XDisplayKeycodes",
  "XDisplayMotionBufferSize",
  "XDisplayName",
  "XDisplayOfIM",
  "XDisplayOfOM",
  "XDisplayOfScreen",
  "XDisplayPlanes",
  "XDisplayString",
  "XDisplayWidth",
  "XDisplayWidthMM",
  "XDoesBackingStore",
  "XDoesSaveUnders",
  "XDrawArc",
  "XDrawArcs",
  "XDrawImageString",
  "XDrawImageString16",
  "XDrawLine",
  "XDrawLines",
  "XDrawPoint",
  "XDrawPoints",
  "XDrawRectangle",
  "XDrawRectangles",
  "XDrawSegments",
  "XDrawString",
  "XDrawString16",
  "XDrawText",
  "XDrawText16",
  "XEHeadOfExtensionList",
  "XESetBeforeFlush",
  "XESetCloseDisplay",
  "XESetCopyEventCookie",
  "XESetCopyGC",
  "XESetCreateFont",
  "XESetCreateGC",
  "XESetError",
  "XESetErrorString",
  "XESetEventToWire",
  "XESetFlushGC",
  "XESetFreeFont",
  "XESetFreeGC",
  "XESetPrintErrorValues",
  "XESetWireToError",
  "XESetWireToEvent",
  "XESetWireToEventCookie",
  "XEmptyRegion",
  "XEnableAccessControl",
  "XEqualRegion",
  "XEventMaskOfScreen",
  "XEventsQueued",
  "XExtendedMaxRequestSize",
  "XExtentsOfFontSet",
  "XFetchBuffer",
  "XFetchBytes",
  "XFetchName",
  "XFillArc",
  "XFillArcs",
  "XFillPolygon",
  "XFillRectangle",
  "XFillRectangles",
  "XFilterEvent",
  "XFindContext",
  "XFindOnExtensionList",
  "XFlush",
  "XFlushGC",
  "XFontsOfFontSet",
  "XForceScreenSaver",
  "XFree",
  "XFreeColormap",
  "XFreeColors",
  "XFreeCursor",
  "XFreeEventData",
  "XFreeExtensionList",
  "XFreeFont",
  "XFreeFontInfo",
  "XFreeFontNames",
  "XFreeFontPath",
  "XFreeFontSet",
  "XFreeGC",
  "XFreeModifiermap",
  "XFreePixmap",
  "XFreeStringList",
  "XGContextFromGC",
  "XGeometry",
  "XGetAtomName",
  "XGetAtomNames",
  "XGetClassHint",
  "XGetCommand",
  "XGetDefault",
  "XGetErrorDatabaseText",
  "XGetErrorText",
  "XGetEventData",
  "XGetFontPath",
  "XGetFontProperty",
  "XGetGCValues",
  "XGetGeometry",
  "XGetICValues",
  "XGetIMValues",
  "XGetIconName",
  "XGetIconSizes",
  "XGetImage",
  "XGetInputFocus",
  "XGetKeyboardControl",
  "XGetKeyboardMapping",
  "XGetModifierMapping",
  "XGetMotionEvents",
  "XGetNormalHints",
  "XGetOCValues",
  "XGetOMValues",
  "XGetPixel",
  "XGetPointerControl",
  "XGetPointerMapping",
  "XGetRGBColormaps",
  "XGetScreenSaver",
  "XGetSelectionOwner",
  "XGetSizeHints",
  "XGetStandardColormap",
  "XGetSubImage",
  "XGetTextProperty",
  "XGetTransientForHint",
  "XGetVisualInfo",
  "XGetWMClientMachine",
  "XGetWMColormapWindows",
  "XGetWMHints",
  "XGetWMIconName",
  "XGetWMName",
  "XGetWMNormalHints",
  "XGetWMProtocols",
  "XGetWMSizeHints",
  "XGetWindowAttributes",
  "XGetWindowProperty",
  "XGetZoomHints",
  "XGrabButton",
  "XGrabKey",
  "XGrabKeyboard",
  "XGrabPointer",
  "XGrabServer",
  "XHeightMMOfScreen",
  "XHeightOfScreen",
  "XIMOfIC",
  "XIconifyWindow",
  "XIfEvent",
  "XImageByteOrder",
  "XInitExtension",
  "XInitImage",
  "XInitThreads",
  "XInsertModifiermapEntry",
  "XInstallColormap",
  "XInternAtom",
  "XInternAtoms",
  "XInternalConnectionNumbers",
  "XIntersectRegion",
  "XKeycodeToKeysym",
  "XKeysymToKeycode",
  "XKeysymToString",
  "XKillClient",
  "XLastKnownRequestProcessed",
  "XListDepths",
  "XListExtensions",
  "XListFonts",
  "XListFontsWithInfo",
  "XListHosts",
  "XListInstalledColormaps",
  "XListPixmapFormats",
  "XListProperties",
  "XLoadFont",
  "XLoadQueryFont",
  "XLocaleOfFontSet",
  "XLocaleOfIM",
  "XLocaleOfOM",
  "XLockDisplay",
  "XLookupColor",
  "XLookupKeysym",
  "XLookupString",
  "XLowerWindow",
  "XMapRaised",
  "XMapSubwindows",
  "XMapWindow",
  "XMaskEvent",
  "XMatchVisualInfo",
  "XMaxCmapsOfScreen",
  "XMaxRequestSize",
  "XMinCmapsOfScreen",
  "XMoveResizeWindow",
  "XMoveWindow",
  "XNewModifiermap",
  "XNextEvent",
  "XNextRequest",
  "XNoOp",
  "XOMOfOC",
  "XOffsetRegion",
  "XOpenDisplay",
  "XOpenIM",
  "XOpenOM",
  "XParseColor",
  "XParseGeometry",
  "XPeekEvent",
  "XPeekIfEvent",
  "XPending",
  "XPlanesOfScreen",
  "XPointInRegion",
  "XPolygonRegion",
  "XProcessInternalConnection",
  "XProtocolRevision",
  "XProtocolVersion",
  "XPutBackEvent",
  "XPutImage",
  "XPutPixel",
  "XQLength",
  "XQueryBestCursor",
  "XQueryBestSize",
  "XQueryBestStipple",
  "XQueryBestTile",
  "XQueryColor",
  "XQueryColors",
  "XQueryExtension",
  "XQueryFont",
  "XQueryKeymap",
  "XQueryPointer",
  "XQueryTextExtents",
  "XQueryTextExtents16",
  "XQueryTree",
  "XRaiseWindow",
  "XReadBitmapFile",
  "XReadBitmapFileData",
  "XRebindKeysym",
  "XRecolorCursor",
  "XReconfigureWMWindow",
  "XRectInRegion",
  "XRefreshKeyboardMapping",
  "XRegisterIMInstantiateCallback",
  "XRemoveConnectionWatch",
  "XRemoveFromSaveSet",
  "XRemoveHost",
  "XRemoveHosts",
  "XReparentWindow",
  "XResetScreenSaver",
  "XResizeWindow",
  "XResourceManagerString",
  "XRestackWindows",
  "XRootWindow",
  "XRootWindowOfScreen",
  "XRotateBuffers",
  "XRotateWindowProperties",
  "XSaveContext",
  "XScreenCount",
  "XScreenNumberOfScreen",
  "XScreenOfDisplay",
  "XScreenResourceString",
  "XSelectInput",
  "XSendEvent",
  "XServerVendor",
  "XSetAccessControl",
  "XSetAfterFunction",
  "XSetArcMode",
  "XSetAuthorization",
  "XSetBackground",
  "XSetClassHint",
  "XSetClipMask",
  "XSetClipOrigin",
  "XSetClipRectangles",
  "XSetCloseDownMode",
  "XSetCommand",
  "XSetDashes",
  "XSetErrorHandler",
  "XSetFillRule",
  "XSetFillStyle",
  "XSetFont",
  "XSetFontPath",
  "XSetForeground",
  "XSetFunction",
  "XSetGraphicsExposures",
  "XSetICFocus",
  "XSetICValues",
  "XSetIMValues",
  "XSetIOErrorHandler",
  "XSetIconName",
  "XSetIconSizes",
  "XSetInputFocus",
  "XSetLineAttributes",
  "XSetLocaleModifiers",
  "XSetModifierMapping",
  "XSetNormalHints",
  "XSetOCValues",
  "XSetOMValues",
  "XSetPlaneMask",
  "XSetPointerMapping",
  "XSetRGBColormaps",
  "XSetRegion",
  "XSetScreenSaver",
  "XSetSelectionOwner",
  "XSetSizeHints",
  "XSetStandardColormap",
  "XSetStandardProperties",
  "XSetState",
  "XSetStipple",
  "XSetSubwindowMode",
  "XSetTSOrigin",
  "XSetTextProperty",
  "XSetTile",
  "XSetTransientForHint",
  "XSetWMClientMachine",
  "XSetWMColormapWindows",
  "XSetWMHints",
  "XSetWMIconName",
  "XSetWMName",
  "XSetWMNormalHints",
  "XSetWMProperties",
  "XSetWMProtocols",
  "XSetWMSizeHints",
  "XSetWindowBackground",
  "XSetWindowBackgroundPixmap",
  "XSetWindowBorder",
  "XSetWindowBorderPixmap",
  "XSetWindowBorderWidth",
  "XSetWindowColormap",
  "XSetZoomHints",
  "XShrinkRegion",
  "XStoreBuffer",
  "XStoreBytes",
  "XStoreColor",
  "XStoreColors",
  "XStoreName",
  "XStoreNamedColor",
  "XStringListToTextProperty",
  "XStringToKeysym",
  "XSubImage",
  "XSubtractRegion",
  "XSupportsLocale",
  "XSync",
  "XSynchronize",
  "XTextExtents",
  "XTextExtents16",
  "XTextPropertyToStringList",
  "XTextWidth",
  "XTextWidth16",
  "XTranslateCoordinates",
  "XUndefineCursor",
  "XUngrabButton",
  "XUngrabKey",
  "XUngrabKeyboard",
  "XUngrabPointer",
  "XUngrabServer",
  "XUninstallColormap",
  "XUnionRectWithRegion",
  "XUnionRegion",
  "XUnloadFont",
  "XUnlockDisplay",
  "XUnmapSubwindows",
  "XUnmapWindow",
  "XUnregisterIMInstantiateCallback",
  "XUnsetICFocus",
  "XVaCreateNestedList",
  "XVendorRelease",
  "XVisualIDFromVisual",
  "XWMGeometry",
  "XWarpPointer",
  "XWhitePixel",
  "XWhitePixelOfScreen",
  "XWidthMMOfScreen",
  "XWidthOfScreen",
  "XWindowEvent",
  "XWithdrawWindow",
  "XWriteBitmapFile",
  "XXorRegion",
  "XcmsAddColorSpace",
  "XcmsAddFunctionSet",
  "XcmsAllocColor",
  "XcmsAllocNamedColor",
  "XcmsCCCOfColormap",
  "XcmsCIELabClipL",
  "XcmsCIELabClipLab",
  "XcmsCIELabClipab",
  "XcmsCIELabQueryMaxC",
  "XcmsCIELabQueryMaxL",
  "XcmsCIELabQueryMaxLC",
  "XcmsCIELabQueryMinL",
  "XcmsCIELabToCIEXYZ",
  "XcmsCIELabWhiteShiftColors",
  "XcmsCIELuvClipL",
  "XcmsCIELuvClipLuv",
  "XcmsCIELuvClipuv",
  "XcmsCIELuvQueryMaxC",
  "XcmsCIELuvQueryMaxL",
  "XcmsCIELuvQueryMaxLC",
  "XcmsCIELuvQueryMinL",
  "XcmsCIELuvToCIEuvY",
  "XcmsCIELuvWhiteShiftColors",
  "XcmsCIEXYZToCIELab",
  "XcmsCIEXYZToCIEuvY",
  "XcmsCIEXYZToCIExyY",
  "XcmsCIEXYZToRGBi",
  "XcmsCIEuvYToCIELuv",
  "XcmsCIEuvYToCIEXYZ",
  "XcmsCIEuvYToTekHVC",
  "XcmsCIExyYToCIEXYZ",
  "XcmsClientWhitePointOfCCC",
  "XcmsConvertColors",
  "XcmsCreateCCC",
  "XcmsDefaultCCC",
  "XcmsDisplayOfCCC",
  "XcmsFormatOfPrefix",
  "XcmsFreeCCC",
  "XcmsLookupColor",
  "XcmsPrefixOfFormat",
  "XcmsQueryBlack",
  "XcmsQueryBlue",
  "XcmsQueryColor",
  "XcmsQueryColors",
  "XcmsQueryGreen",
  "XcmsQueryRed",
  "XcmsQueryWhite",
  "XcmsRGBToRGBi",
  "XcmsRGBiToCIEXYZ",
  "XcmsRGBiToRGB",
  "XcmsScreenNumberOfCCC",
  "XcmsScreenWhitePointOfCCC",
  "XcmsSetCCCOfColormap",
  "XcmsSetCompressionProc",
  "XcmsSetWhiteAdjustProc",
  "XcmsSetWhitePoint",
  "XcmsStoreColor",
  "XcmsStoreColors",
  "XcmsTekHVCClipC",
  "XcmsTekHVCClipV",
  "XcmsTekHVCClipVC",
  "XcmsTekHVCQueryMaxC",
  "XcmsTekHVCQueryMaxV",
  "XcmsTekHVCQueryMaxVC",
  "XcmsTekHVCQueryMaxVSamples",
  "XcmsTekHVCQueryMinV",
  "XcmsTekHVCToCIEuvY",
  "XcmsTekHVCWhiteShiftColors",
  "XcmsVisualOfCCC",
  "XkbAddDeviceLedInfo",
  "XkbAddGeomColor",
  "XkbAddGeomDoodad",
  "XkbAddGeomKey",
  "XkbAddGeomKeyAlias",
  "XkbAddGeomOutline",
  "XkbAddGeomOverlay",
  "XkbAddGeomOverlayKey",
  "XkbAddGeomOverlayRow",
  "XkbAddGeomProperty",
  "XkbAddGeomRow",
  "XkbAddGeomSection",
  "XkbAddGeomShape",
  "XkbAddKeyType",
  "XkbAllocClientMap",
  "XkbAllocCompatMap",
  "XkbAllocControls",
  "XkbAllocDeviceInfo",
  "XkbAllocGeomColors",
  "XkbAllocGeomDoodads",
  "XkbAllocGeomKeyAliases",
  "XkbAllocGeomKeys",
  "XkbAllocGeomOutlines",
  "XkbAllocGeomOverlayKeys",
  "XkbAllocGeomOverlayRows",
  "XkbAllocGeomOverlays",
  "XkbAllocGeomPoints",
  "XkbAllocGeomProps",
  "XkbAllocGeomRows",
  "XkbAllocGeomSectionDoodads",
  "XkbAllocGeomSections",
  "XkbAllocGeomShapes",
  "XkbAllocGeometry",
  "XkbAllocIndicatorMaps",
  "XkbAllocKeyboard",
  "XkbAllocNames",
  "XkbAllocServerMap",
  "XkbApplyCompatMapToKey",
  "XkbApplyVirtualModChanges",
  "XkbBell",
  "XkbBellEvent",
  "XkbChangeDeviceInfo",
  "XkbChangeEnabledControls",
  "XkbChangeKeycodeRange",
  "XkbChangeMap",
  "XkbChangeNames",
  "XkbChangeTypesOfKey",
  "XkbComputeEffectiveMap",
  "XkbComputeRowBounds",
  "XkbComputeSectionBounds",
  "XkbComputeShapeBounds",
  "XkbComputeShapeTop",
  "XkbCopyKeyType",
  "XkbCopyKeyTypes",
  "XkbDeviceBell",
  "XkbDeviceBellEvent",
  "XkbFindOverlayForKey",
  "XkbForceBell",
  "XkbForceDeviceBell",
  "XkbFreeClientMap",
  "XkbFreeCompatMap",
  "XkbFreeComponentList",
  "XkbFreeControls",
  "XkbFreeDeviceInfo",
  "XkbFreeGeomColors",
  "XkbFreeGeomDoodads",
  "XkbFreeGeomKeyAliases",
  "XkbFreeGeomKeys",
  "XkbFreeGeomOutlines",
  "XkbFreeGeomOverlayKeys",
  "XkbFreeGeomOverlayRows",
  "XkbFreeGeomOverlays",
  "XkbFreeGeomPoints",
  "XkbFreeGeomProperties",
  "XkbFreeGeomRows",
  "XkbFreeGeomSections",
  "XkbFreeGeomShapes",
  "XkbFreeGeometry",
  "XkbFreeIndicatorMaps",
  "XkbFreeKeyboard",
  "XkbFreeNames",
  "XkbFreeServerMap",
  "XkbGetAutoRepeatRate",
  "XkbGetAutoResetControls",
  "XkbGetCompatMap",
  "XkbGetControls",
  "XkbGetDetectableAutoRepeat",
  "XkbGetDeviceButtonActions",
  "XkbGetDeviceInfo",
  "XkbGetDeviceInfoChanges",
  "XkbGetDeviceLedInfo",
  "XkbGetGeometry",
  "XkbGetIndicatorMap",
  "XkbGetIndicatorState",
  "XkbGetKeyActions",
  "XkbGetKeyBehaviors",
  "XkbGetKeyExplicitComponents",
  "XkbGetKeyModifierMap",
  "XkbGetKeySyms",
  "XkbGetKeyTypes",
  "XkbGetKeyVirtualModMap",
  "XkbGetKeyboard",
  "XkbGetKeyboardByName",
  "XkbGetMap",
  "XkbGetMapChanges",
  "XkbGetNamedDeviceIndicator",
  "XkbGetNamedGeometry",
  "XkbGetNamedIndicator",
  "XkbGetNames",
  "XkbGetPerClientControls",
  "XkbGetState",
  "XkbGetUpdatedMap",
  "XkbGetVirtualMods",
  "XkbGetXlibControls",
  "XkbIgnoreExtension",
  "XkbInitCanonicalKeyTypes",
  "XkbKeyTypesForCoreSymbols",
  "XkbKeycodeToKeysym",
  "XkbKeysymToModifiers",
  "XkbLatchGroup",
  "XkbLatchModifiers",
  "XkbLibraryVersion",
  "XkbListComponents",
  "XkbLockGroup",
  "XkbLockModifiers",
  "XkbLookupKeyBinding",
  "XkbLookupKeySym",
  "XkbNoteControlsChanges",
  "XkbNoteDeviceChanges",
  "XkbNoteMapChanges",
  "XkbNoteNameChanges",
  "XkbOpenDisplay",
  "XkbQueryExtension",
  "XkbRefreshKeyboardMapping",
  "XkbResizeDeviceButtonActions",
  "XkbResizeKeyActions",
  "XkbResizeKeySyms",
  "XkbResizeKeyType",
  "XkbSelectEventDetails",
  "XkbSelectEvents",
  "XkbSetAtomFuncs",
  "XkbSetAutoRepeatRate",
  "XkbSetAutoResetControls",
  "XkbSetCompatMap",
  "XkbSetControls",
  "XkbSetDebuggingFlags",
  "XkbSetDetectableAutoRepeat",
  "XkbSetDeviceButtonActions",
  "XkbSetDeviceInfo",
  "XkbSetDeviceLedInfo",
  "XkbSetGeometry",
  "XkbSetIgnoreLockMods",
  "XkbSetIndicatorMap",
  "XkbSetMap",
  "XkbSetNamedDeviceIndicator",
  "XkbSetNamedIndicator",
  "XkbSetNames",
  "XkbSetPerClientControls",
  "XkbSetServerInternalMods",
  "XkbSetXlibControls",
  "XkbToControl",
  "XkbTranslateKey",
  "XkbTranslateKeyCode",
  "XkbTranslateKeySym",
  "XkbUpdateActionVirtualMods",
  "XkbUpdateKeyTypeVirtualMods",
  "XkbUpdateMapFromCore",
  "XkbUseExtension",
  "XkbVirtualModsToReal",
  "XkbXlibControlsImplemented",
  "XmbDrawImageString",
  "XmbDrawString",
  "XmbDrawText",
  "XmbLookupString",
  "XmbResetIC",
  "XmbSetWMProperties",
  "XmbTextEscapement",
  "XmbTextExtents",
  "XmbTextListToTextProperty",
  "XmbTextPerCharExtents",
  "XmbTextPropertyToTextList",
  "Xpermalloc",
  "XrmCombineDatabase",
  "XrmCombineFileDatabase",
  "XrmDestroyDatabase",
  "XrmEnumerateDatabase",
  "XrmGetDatabase",
  "XrmGetFileDatabase",
  "XrmGetResource",
  "XrmGetStringDatabase",
  "XrmInitialize",
  "XrmLocaleOfDatabase",
  "XrmMergeDatabases",
  "XrmParseCommand",
  "XrmPermStringToQuark",
  "XrmPutFileDatabase",
  "XrmPutLineResource",
  "XrmPutResource",
  "XrmPutStringResource",
  "XrmQGetResource",
  "XrmQGetSearchList",
  "XrmQGetSearchResource",
  "XrmQPutResource",
  "XrmQPutStringResource",
  "XrmQuarkToString",
  "XrmSetDatabase",
  "XrmStringToBindingQuarkList",
  "XrmStringToQuark",
  "XrmStringToQuarkList",
  "XrmUniqueQuark",
  "Xutf8DrawImageString",
  "Xutf8DrawString",
  "Xutf8DrawText",
  "Xutf8LookupString",
  "Xutf8ResetIC",
  "Xutf8SetWMProperties",
  "Xutf8TextEscapement",
  "Xutf8TextExtents",
  "Xutf8TextListToTextProperty",
  "Xutf8TextPerCharExtents",
  "Xutf8TextPropertyToTextList",
  "XwcDrawImageString",
  "XwcDrawString",
  "XwcDrawText",
  "XwcFreeStringList",
  "XwcLookupString",
  "XwcResetIC",
  "XwcTextEscapement",
  "XwcTextExtents",
  "XwcTextListToTextProperty",
  "XwcTextPerCharExtents",
  "XwcTextPropertyToTextList",
  "_Utf8GetConvByName",
  "_XAllocID",
  "_XAllocIDs",
  "_XAllocScratch",
  "_XAllocTemp",
  "_XAsyncErrorHandler",
  "_XCloseLC",
  "_XColor_to_XcmsRGB",
  "_XConnectXCB",
  "_XCopyEventCookie",
  "_XCopyToArg",
  "_XData32",
  "_XDefaultError",
  "_XDefaultIOError",
  "_XDefaultOpenIM",
  "_XDefaultOpenOM",
  "_XDefaultWireError",
  "_XDeq",
  "_XDeqAsyncHandler",
  "_XEatData",
  "_XEatDataWords",
  "_XEnq",
  "_XError",
  "_XEventToWire",
  "_XEventsQueued",
  "_XF86BigfontFreeFontMetrics",
  "_XF86LoadQueryLocaleFont",
  "_XFetchEventCookie",
  "_XFlush",
  "_XFlushGCCache",
  "_XFreeAtomTable",
  "_XFreeDisplayStructure",
  "_XFreeEventCookies",
  "_XFreeExtData",
  "_XFreeTemp",
  "_XFreeX11XCBStructure",
  "_XGetAsyncData",
  "_XGetAsyncReply",
  "_XGetBitsPerPixel",
  "_XGetHostname",
  "_XGetLCValues",
  "_XGetRequest",
  "_XGetScanlinePad",
  "_XGetWindowAttributes",
  "_XIMCompileResourceList",
  "_XIOError",
  "_XInitIM",
  "_XInitImageFuncPtrs",
  "_XInitKeysymDB",
  "_XInitOM",
  "_XIsEventCookie",
  "_XKeyInitialize",
  "_XKeycodeToKeysym",
  "_XKeysymToKeycode",
  "_XKeysymToModifiers",
  "_XLookupKeysym",
  "_XLookupString",
  "_XNoticeCreateBitmap",
  "_XNoticePutBitmap",
  "_XOpenLC",
  "_XParseBaseFontNameList",
  "_XPollfdCacheAdd",
  "_XPollfdCacheDel",
  "_XPollfdCacheInit",
  "_XProcessInternalConnection",
  "_XProcessWindowAttributes",
  "_XPutBackEvent",
  "_XRead",
  "_XRead32",
  "_XReadEvents",
  "_XReadPad",
  "_XRefreshKeyboardMapping",
  "_XRegisterFilterByMask",
  "_XRegisterFilterByType",
  "_XRegisterInternalConnection",
  "_XReply",
  "_XReverse_Bytes",
  "_XScreenOfWindow",
  "_XSend",
  "_XSetClipRectangles",
  "_XSetImage",
  "_XSetLastRequestRead",
  "_XStoreEventCookie",
  "_XTextHeight",
  "_XTextHeight16",
  "_XTranslateKey",
  "_XTranslateKeySym",
  "_XTryShapeBitmapCursor",
  "_XUnknownCopyEventCookie",
  "_XUnknownNativeEvent",
  "_XUnknownWireEvent",
  "_XUnknownWireEventCookie",
  "_XUnregisterFilter",
  "_XUnregisterInternalConnection",
  "_XUnresolveColor",
  "_XUpdateAtomCache",
  "_XUpdateGCCache",
  "_XVIDtoVisual",
  "_XWireToEvent",
  "_XcmsAddCmapRec",
  "_XcmsArcTangent",
  "_XcmsCIELabQueryMaxLCRGB",
  "_XcmsCIELuvQueryMaxLCRGB",
  "_XcmsCIEXYZ_ValidSpec",
  "_XcmsCIEuvY_ValidSpec",
  "_XcmsConvertColorsWithWhitePt",
  "_XcmsCopyCmapRecAndFree",
  "_XcmsCopyISOLatin1Lowered",
  "_XcmsCopyPointerArray",
  "_XcmsCosine",
  "_XcmsCubeRoot",
  "_XcmsDDConvertColors",
  "_XcmsDIConvertColors",
  "_XcmsDeleteCmapRec",
  "_XcmsEqualWhitePts",
  "_XcmsFreeIntensityMaps",
  "_XcmsFreePointerArray",
  "_XcmsGetElement",
  "_XcmsGetIntensityMap",
  "_XcmsGetProperty",
  "_XcmsInitDefaultCCCs",
  "_XcmsInitScrnInfo",
  "_XcmsLRGB_InitScrnDefault",
  "_XcmsPushPointerArray",
  "_XcmsRGB_to_XColor",
  "_XcmsRegFormatOfPrefix",
  "_XcmsResolveColor",
  "_XcmsResolveColorString",
  "_XcmsSetGetColor",
  "_XcmsSetGetColors",
  "_XcmsSine",
  "_XcmsSquareRoot",
  "_XcmsTekHVCQueryMaxVCRGB",
  "_XcmsTekHVC_CheckModify",
  "_XcmsUnresolveColor",
  "_XimCbDispatch",
  "_XimCheckCreateICValues",
  "_XimCheckDataSize",
  "_XimCheckICMode",
  "_XimCheckIMMode",
  "_XimCheckIfLocalProcessing",
  "_XimCheckIfThaiProcessing",
  "_XimCheckLocalInputStyle",
  "_XimCommitCallback",
  "_XimConnect",
  "_XimDecodeICATTRIBUTE",
  "_XimDecodeIMATTRIBUTE",
  "_XimDecodeLocalICAttr",
  "_XimDecodeLocalIMAttr",
  "_XimDestroyIMStructureList",
  "_XimDispatchInit",
  "_XimEncodeICATTRIBUTE",
  "_XimEncodeIMATTRIBUTE",
  "_XimEncodeLocalICAttr",
  "_XimEncodeLocalIMAttr",
  "_XimError",
  "_XimErrorCallback",
  "_XimExtension",
  "_XimFilterWaitEvent",
  "_XimFlush",
  "_XimForwardEvent",
  "_XimForwardEventCallback",
  "_XimFreeCommitInfo",
  "_XimFreeProtoIntrCallback",
  "_XimFreeTransIntrCallback",
  "_XimGetAttributeID",
  "_XimGetCharCode",
  "_XimGetCurrentICValues",
  "_XimGetCurrentIMValues",
  "_XimGetICValueData",
  "_XimGetIMValueData",
  "_XimGetLocaleCode",
  "_XimGetMyEndian",
  "_XimGetResourceListRec",
  "_XimGetResourceListRecByQuark",
  "_XimGetWindowEventmask",
  "_XimICOfXICID",
  "_XimInitialResourceInfo",
  "_XimLcctstombs",
  "_XimLcctstoutf8",
  "_XimLcctstowcs",
  "_XimLocalCreateIC",
  "_XimLocalFilter",
  "_XimLocalGetICValues",
  "_XimLocalGetIMValues",
  "_XimLocalIMFree",
  "_XimLocalMbLookupString",
  "_XimLocalOpenIM",
  "_XimLocalSetICValues",
  "_XimLocalSetIMValues",
  "_XimLocalUtf8LookupString",
  "_XimLocalWcLookupString",
  "_XimLookupMBText",
  "_XimLookupUTF8Text",
  "_XimLookupWCText",
  "_XimMakeICAttrIDList",
  "_XimMakeIMAttrIDList",
  "_XimOpenIM",
  "_XimParseStringFile",
  "_XimProcError",
  "_XimProcSyncReply",
  "_XimProtoCreateIC",
  "_XimProtoEventToWire",
  "_XimProtoIMFree",
  "_XimProtoMbLookupString",
  "_XimProtoOpenIM",
  "_XimProtoUtf8LookupString",
  "_XimProtoWcLookupString",
  "_XimProtoWireToEvent",
  "_XimRead",
  "_XimRegProtoIntrCallback",
  "_XimRegisterDispatcher",
  "_XimRegisterFilter",
  "_XimRegisterIMInstantiateCallback",
  "_XimRegisterServerFilter",
  "_XimRegisterTriggerKeysCallback",
  "_XimReregisterFilter",
  "_XimResetIMInstantiateCallback",
  "_XimRespSyncReply",
  "_XimServerDestroy",
  "_XimSetCurrentICValues",
  "_XimSetCurrentIMValues",
  "_XimSetEventMaskCallback",
  "_XimSetHeader",
  "_XimSetICDefaults",
  "_XimSetICMode",
  "_XimSetICResourceList",
  "_XimSetICValueData",
  "_XimSetIMMode",
  "_XimSetIMResourceList",
  "_XimSetIMValueData",
  "_XimSetInnerICResourceList",
  "_XimSetInnerIMResourceList",
  "_XimSetLocalIMDefaults",
  "_XimShutdown",
  "_XimSync",
  "_XimSyncCallback",
  "_XimThaiCloseIM",
  "_XimThaiCreateIC",
  "_XimThaiFilter",
  "_XimThaiIMFree",
  "_XimThaiOpenIM",
  "_XimTransCallDispatcher",
  "_XimTransConf",
  "_XimTransFilterWaitEvent",
  "_XimTransFlush",
  "_XimTransInternalConnection",
  "_XimTransRead",
  "_XimTransRegisterDispatcher",
  "_XimTransWrite",
  "_XimTriggerNotify",
  "_XimUnRegisterIMInstantiateCallback",
  "_XimUnregisterFilter",
  "_XimUnregisterServerFilter",
  "_XimWrite",
  "_XimXConf",
  "_XimXTransBytesReadable",
  "_XimXTransClose",
  "_XimXTransCloseForCloning",
  "_XimXTransConnect",
  "_XimXTransDisconnect",
  "_XimXTransFreeConnInfo",
  "_XimXTransGetConnectionNumber",
  "_XimXTransGetHostname",
  "_XimXTransGetPeerAddr",
  "_XimXTransIsLocal",
  "_XimXTransOpenCOTSClient",
  "_XimXTransRead",
  "_XimXTransReadv",
  "_XimXTransSetOption",
  "_XimXTransWrite",
  "_XimXTransWritev",
  "_Ximctstombs",
  "_Ximctstoutf8",
  "_Ximctstowcs",
  "_XkbCopyFromReadBuffer",
  "_XkbFreeReadBuffer",
  "_XkbGetCharset",
  "_XkbGetConverters",
  "_XkbGetReadBufferCountedString",
  "_XkbGetReadBufferPtr",
  "_XkbInitReadBuffer",
  "_XkbNoteCoreMapChanges",
  "_XkbPeekAtReadBuffer",
  "_XkbReadBufferCopy32",
  "_XkbReadBufferCopyKeySyms",
  "_XkbReadCopyData32",
  "_XkbReadCopyKeySyms",
  "_XkbReadGetCompatMapReply",
  "_XkbReadGetGeometryReply",
  "_XkbReadGetIndicatorMapReply",
  "_XkbReadGetMapReply",
  "_XkbReadGetNamesReply",
  "_XkbReloadDpy",
  "_XkbSkipReadBufferData",
  "_XkbWriteCopyData32",
  "_XkbWriteCopyKeySyms",
  "_XlcAddCT",
  "_XlcAddCharSet",
  "_XlcAddGB18030LocaleConverters",
  "_XlcAddLoader",
  "_XlcAddUtf8Converters",
  "_XlcAddUtf8LocaleConverters",
  "_XlcCloseConverter",
  "_XlcCompareISOLatin1",
  "_XlcCompileResourceList",
  "_XlcConvert",
  "_XlcCopyFromArg",
  "_XlcCopyToArg",
  "_XlcCountVaList",
  "_XlcCreateDefaultCharSet",
  "_XlcCreateLC",
  "_XlcCreateLocaleDataBase",
  "_XlcCurrentLC",
  "_XlcDbg_printValue",
  "_XlcDeInitLoader",
  "_XlcDefaultLoader",
  "_XlcDefaultMapModifiers",
  "_XlcDestroyLC",
  "_XlcDestroyLocaleDataBase",
  "_XlcFileName",
  "_XlcGenericLoader",
  "_XlcGetCSValues",
  "_XlcGetCharSet",
  "_XlcGetCharSetWithSide",
  "_XlcGetLocaleDataBase",
  "_XlcGetResource",
  "_XlcGetValues",
  "_XlcInitCTInfo",
  "_XlcInitLoader",
  "_XlcLocaleDirName",
  "_XlcLocaleLibDirName",
  "_XlcMapOSLocaleName",
  "_XlcNCompareISOLatin1",
  "_XlcOpenConverter",
  "_XlcParseCharSet",
  "_XlcParse_scopemaps",
  "_XlcRemoveLoader",
  "_XlcResetConverter",
  "_XlcResolveI18NPath",
  "_XlcResolveLocaleName",
  "_XlcSetConverter",
  "_XlcSetValues",
  "_XlcUtf8Loader",
  "_XlcVaToArgList",
  "_XlcValidModSyntax",
  "_Xlcmbstoutf8",
  "_Xlcmbstowcs",
  "_Xlcmbtowc",
  "_Xlcwcstombs",
  "_Xlcwctomb",
  "_XmbDefaultDrawImageString",
  "_XmbDefaultDrawString",
  "_XmbDefaultTextEscapement",
  "_XmbDefaultTextExtents",
  "_XmbDefaultTextPerCharExtents",
  "_XmbGenericDrawImageString",
  "_XmbGenericDrawString",
  "_XmbGenericTextEscapement",
  "_XmbGenericTextExtents",
  "_XmbGenericTextPerCharExtents",
  "_XmbTextListToTextProperty",
  "_XmbTextPropertyToTextList",
  "_Xmblen",
  "_Xmbstoutf8",
  "_Xmbstowcs",
  "_Xmbtowc",
  "_XomConvert",
  "_XomGenericDrawString",
  "_XomGenericOpenOM",
  "_XomGenericTextExtents",
  "_XomGetFontDataFromFontSet",
  "_XomInitConverter",
  "_XrmDefaultInitParseInfo",
  "_XrmInitParseInfo",
  "_XrmInternalStringToQuark",
  "_Xutf8DefaultDrawImageString",
  "_Xutf8DefaultDrawString",
  "_Xutf8DefaultTextEscapement",
  "_Xutf8DefaultTextExtents",
  "_Xutf8DefaultTextPerCharExtents",
  "_Xutf8GenericDrawImageString",
  "_Xutf8GenericDrawString",
  "_Xutf8GenericTextEscapement",
  "_Xutf8GenericTextExtents",
  "_Xutf8GenericTextPerCharExtents",
  "_Xutf8TextListToTextProperty",
  "_Xutf8TextPropertyToTextList",
  "_XwcDefaultDrawImageString",
  "_XwcDefaultDrawString",
  "_XwcDefaultTextEscapement",
  "_XwcDefaultTextExtents",
  "_XwcDefaultTextPerCharExtents",
  "_XwcFreeStringList",
  "_XwcGenericDrawImageString",
  "_XwcGenericDrawString",
  "_XwcGenericTextEscapement",
  "_XwcGenericTextExtents",
  "_XwcGenericTextPerCharExtents",
  "_XwcTextListToTextProperty",
  "_XwcTextPropertyToTextList",
  "_Xwcscmp",
  "_Xwcscpy",
  "_Xwcslen",
  "_Xwcsncmp",
  "_Xwcsncpy",
  "_Xwcstombs",
  "_Xwctomb",
  "read_EncodingInfo",
  "xlocaledir",
  0
};

extern void *_libX11_so_tramp_table[];

// Can be sped up by manually parsing library symtab...
void _libX11_so_tramp_resolve(int i) {
  assert((unsigned)i + 1 < sizeof(sym_names) / sizeof(sym_names[0]));

  CHECK(!is_lib_loading, "library function '%s' called during library load", sym_names[i]);

  void *h = 0;
#if NO_DLOPEN
  // FIXME: instead of RTLD_NEXT we should search for loaded lib_handle
  // as in https://github.com/jethrogb/ssltrace/blob/bf17c150a7/ssltrace.cpp#L74-L112
  h = RTLD_NEXT;
#elif LAZY_LOAD
  h = load_library();
#else
  h = lib_handle;
  CHECK(h, "failed to resolve symbol '%s', library failed to load", sym_names[i]);
#endif

  // Dlsym is thread-safe so don't need to protect it.
  _libX11_so_tramp_table[i] = dlsym(h, sym_names[i]);
  CHECK(_libX11_so_tramp_table[i], "failed to resolve symbol '%s'", sym_names[i]);
}

// Helper for user to resolve all symbols
void _libX11_so_tramp_resolve_all(void) {
  size_t i;
  for(i = 0; i + 1 < sizeof(sym_names) / sizeof(sym_names[0]); ++i)
    _libX11_so_tramp_resolve(i);
}

#ifdef __cplusplus
}  // extern "C"
#endif
